/**
 * 标注类
 */
export default class Annotation {
  /**
   * 构造标注
   * @param {*} view view 对象
   * @param {*} paper paper 对象
   * @param {*} id 标注的id
   * @param {*} points 标注的点
   * @param {*} option 选项
   *  {
   *      lineWidth // 线宽
   *      childStrokeDash // 虚线中线段的长
   *      childStrokeGap // 虚线中空白的长
   *      pointSize // 点大小
   *      pixelsPerMeter // 比例尺
   *      color // 颜色
   *      className // 类型名称
   *  }
   */
  constructor(view, paper, id, points, option) {
    this.id = id
    this.view = view
    this.paper = paper

    this.points = points.map(p => new paper.Point(p[1], p[2]))

    this.option = {
      childStrokeDash: 6,
      childStrokeGap: 4,
      color: '#ffffff',
      lineWidth: 10,
      pointSize: 10,
      pixelsPerMeter: 0,
      className: '-1',
      name: '',
      fontSize: 12,
      type: ''
    }
    this.option = _.assign(this.option, option)
    this.circlePoint = {}
    this.path = null // 图形对象
    this.circlePath = null // 图形对象
    this.data = {} // 基本信息长宽面积等数据
    this.isDrawing = false // 是否处于绘制中
    this.pointObjectList = [] // 用来存储显示的点的对象

    // 用来存储当前节点的子节点，子节点的显示区域表示扣除；
    this.children = []
  }

  /**
   *计算获取实时缩放后的大小
   * @param {*} distance 点或线段尺寸
   * @returns 计算后等比缩放的尺寸
   */
  __getRealDistance(distance) {
    const firstPoint = view.viewToProject(new paper.Point(0, distance))
    const secondPoint = view.viewToProject(new paper.Point(0, 0))

    return firstPoint.getDistance(secondPoint)
  }

  /**
   *绘制左侧标注列表小图
   * @returns 包含左侧标注小图的data URL
   */
  __getPathImage() {
    if (!this.path) {
      return null
    }

    const { x } = this.path.bounds
    const { y } = this.path.bounds
    const { width } = this.path.bounds
    const { height } = this.path.bounds
    let blankLeft = 0
    let blankTop = 0

    blankLeft += width * 0.1
    blankTop += height * 0.1
    // 获取点列表，所有点均进行了一定的平移
    const pointList = this.path.segments.map(segment => ({
      x: (segment.point.x + blankLeft - x) / 10,
      y: (segment.point.y + blankTop - y) / 10
    }))

    const canvas = document.createElement('canvas')
    canvas.width = (width * 1.2) / 10
    canvas.height = (height * 1.2) / 10
    const destCtx = canvas.getContext('2d')
    // 底色填充，返回jpg时使用
    destCtx.fillStyle = '#fff'
    destCtx.fillRect(0, 0, canvas.width, canvas.height)
    // 设置线条颜色及宽度
    destCtx.strokeStyle = this.option.color
    destCtx.lineWidth = canvas.width / 50

    // 绘制线条
    destCtx.beginPath()
    pointList.forEach((point, index) => {
      if (index === 0) {
        destCtx.moveTo(point.x, point.y)
      } else {
        destCtx.lineTo(point.x, point.y)
      }
    })
    destCtx.closePath()
    destCtx.stroke()

    return canvas.toDataURL('image/jpeg', 0.1)
  }

  /**
   *绘制标注的点（起始点以及多边形点）
   * @param {*} centerPoint 鼠标点击的位置作为中心点
   */
  __drawAnnotationPoint(centerPoint) {
    const topLeft = new this.paper.Point(
      centerPoint.x - this.__getRealDistance(this.option.pointSize / 2),
      centerPoint.y - this.__getRealDistance(this.option.pointSize / 2)
    )
    const rectSize = new this.paper.Size(
      this.__getRealDistance(this.option.pointSize),
      this.__getRealDistance(this.option.pointSize)
    )
    const rect = new this.paper.Path.Rectangle(topLeft, rectSize)
    // rect.fillColor = '#5446ff'
    const annotationsPoint = new Symbol(rect)

    return annotationsPoint.place(centerPoint)
  }

  /**
   *绘制标注
   */
  draw() {
    let _this = this
    if (_this.option.type == 'circle') {
      _this.drawCircle(_this.points[0], _this.points[1])
    } else {
      const path = new _this.paper.Path({
        segments: _this.points,
        strokeColor: _this.option.color,
        strokeWidth: _this.__getRealDistance(_this.option.lineWidth)
      })

      if (_this.option.show === false) {
        path.opacity = 0
      }
      if (_this.option.fill) {
        const color = new _this.paper.Color(_this.option.color)
        color.alpha = 0.3
        // path.fillColor = color
      }
      this.path = path
    }
    _this.initData()
    return _this
  }

  /**
   * 计算面积等数据
   */
  initData() {
    this.data.image = this.__getPathImage()
    if (this.path) {
      this.data.minX = this.path.bounds.x
      this.data.minY = this.path.bounds.y
      this.data.pixelsWidth = this.path.bounds.width
      this.data.pixelsHeight = this.path.bounds.height
      this.data.pixelsArea = Math.abs(this.path.area)
    }
    if (this.option.pixelsPerMeter > 0) {
      this.data.width = this.data.pixelsWidth / this.option.pixelsPerMeter
      this.data.height = this.data.pixelsHeight / this.option.pixelsPerMeter
      this.data.area =
        this.data.pixelsArea / (this.option.pixelsPerMeter * this.option.pixelsPerMeter)
    }

    return this
  }

  /**
   *设置缩放后的线宽
   *
   * @param {*} lineWidth 原始线宽
   * @memberof Annotation
   */
  setLineWidth(lineWidth) {
    this.option.lineWidth = lineWidth
    if (this.path) {
      this.path.strokeWidth = this.__getRealDistance(lineWidth)
    }
    if (this.circlePath) {
      this.circlePath.strokeWidth = this.__getRealDistance(lineWidth)
    }
    if (this.text) {
      const minX = parseFloat(this.data.minX)
      const minY = parseFloat(this.data.minY)
      const middleX =
        parseFloat(
          this.data.pixelsWidth -
            (this.textContent.length * this.__getRealDistance(this.option.fontSize)) / 2
        ) /
          2 +
        minX
      const middleY = parseFloat(this.data.pixelsHeight) / 2 + minY
      this.text.set({
        point: new paper.Point(middleX, middleY),
        fontSize: this.__getRealDistance(this.option.fontSize)
      })
    }
    if (this.isChildren) {
      this.path.dashArray = [
        this.__getRealDistance(this.option.childStrokeDash),
        this.__getRealDistance(this.option.childStrokeGap)
      ]
    }
    this.children.forEach(child => {
      child.setLineWidth(lineWidth)
    })
    return this
  }

  setColorClass(colorClass) {
    if (!colorClass) {
      return this
    }
    if (this.option.color === colorClass.color) {
      return this
    }
    this.option.color = colorClass.color
    this.data.classToSet = colorClass
    if (this.path) {
      this.path.strokeColor = this.option.color
    }
    this.children.forEach(child => {
      child.setColorClass(colorClass)
    })
    this.data.image = this.__getPathImage()
    return this
  }

  setText(text) {
    if (!this.data) {
      throw '请先初始化数据'
    }

    if (this.textContent === `${text}`) {
      return this
    }
    this.textContent = `${text}`

    const minX = parseFloat(this.data.minX)
    const minY = parseFloat(this.data.minY)
    const middleX =
      parseFloat(
        this.data.pixelsWidth -
          (this.textContent.length * this.__getRealDistance(this.option.fontSize)) / 2
      ) /
        2 +
      minX
    const middleY = parseFloat(this.data.pixelsHeight) / 2 + minY

    if (!this.text) {
      this.text = new PointText({
        point: new paper.Point(middleX, middleY),
        content: this.textContent,
        fillColor: 'black',
        fontFamily: 'Courier New',
        fontWeight: 'bold',
        fontSize: this.__getRealDistance(this.option.fontSize)
      })
    } else {
      this.text.set({
        content: `${this.textContent}`,
        point: new Point(middleX, middleY)
      })
    }
  }

  setOpacity(opacity) {
    this.path.opacity = opacity
    this.children.forEach(child => {
      child.setOpacity(opacity)
    })
  }

  setInfo(name, content) {
    if (name) {
      this.data.name = name
    }
    if (content) {
      this.data.content = content
    }
  }

  /**
   * 设置标注是否正在绘制中
   * @param {boolean} isDrawing
   */
  setDrawing(isDrawing) {
    if (!this.path) {
      return this
    }

    if (isDrawing) {
      this.path.closed = false
    } else {
      this.path.closed = true
    }

    this.isDrawing = isDrawing
    return this
  }

  /** 选择状态 */
  selected(selected) {
    if (this.path) {
      this.path.selected = selected
    }
  }

  addPoint(point, isShow) {
    if (this.path) {
      this.points.push(point)
      this.path.add(point)
      if (isShow) {
        this.pointObjectList.push(this.__drawAnnotationPoint(point))
      }
      this.view.draw()
    }

    return this
  }

  changePoints(points) {
    if (this.path) {
      this.points = []
      this.path.removeSegments()
      points.forEach(point => {
        this.addPoint(point)
      })
    }
  }

  addCirclePoint(beginPoint, mousePoint) {
    this.circlePoint.beginPoint = beginPoint
    this.circlePoint.mousePoint = mousePoint
    if (this.path) {
      this.path.add(beginPoint)
    }
    let dx = Math.abs(mousePoint.x - beginPoint.x)
    let dy = Math.abs(mousePoint.y - beginPoint.y)
    let dis = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2))
    this.circlePath = new this.paper.Path.Circle(beginPoint, dis)
    this.circlePath.strokeWidth = this.__getRealDistance(this.option.lineWidth)
    this.circlePath.strokeColor = this.option.color
    return this
  }

  drawCircle(beginPoint, mousePoint) {
    this.points = [beginPoint, mousePoint]
    if (this.circlePath) {
      this.circlePath.remove()
    }
    this.addCirclePoint(beginPoint, mousePoint)
  }

  hidePoints() {
    this.pointObjectList.forEach(item => {
      item.remove()
    })
  }

  /**
   * 判断一个 annotation 对象形状是不是完全被当前对象包含
   * @param {annotation} annotation
   */
  containTest(annotation) {
    let findFill = true
    if (!this.path.fillColor) {
      // 加入遮罩
      this.path.fillColor = new Color(1, 0, 0, 0.000000001)
      findFill = false
    }

    for (let i = 0; i < annotation.points.length; i++) {
      if (!this.path.hitTest(annotation.points[i])) {
        if (!findFill) {
          this.path.fillColor = null
        }

        return false
      }
    }
    if (!findFill) {
      this.path.fillColor = null
    }
    return true
  }

  /**
   * 为当前对象增加子节点
   * @param {annotation} annotation
   */
  addChildren(annotation) {
    annotation.setColorClass(this.data.classToSet)
    annotation.path.dashArray = [
      this.__getRealDistance(this.option.childStrokeDash),
      this.__getRealDistance(this.option.childStrokeGap)
    ]
    annotation.isChildren = true
    annotation.parentId = this.id
    this.children.push(annotation)
  }

  /**
   * 为当前对象增加虚线
   * @param {annotation} annotation
   */
  addDottedLine(annotation) {
    annotation.setColorClass(this.data.classToSet)
    annotation.path.dashArray = [
      this.__getRealDistance(this.option.childStrokeDash),
      this.__getRealDistance(this.option.childStrokeGap)
    ]
  }

  /**
   *
   */
  hitTest(point) {
    let _this = this
    let hitRes
    for (let i = 0; i < _this.children.length; i++) {
      const hitRes = _this.children[i].hitTest(point)
      if (hitRes) {
        return hitRes
      }
    }
    if (_this.option.type == 'circle') {
      hitRes = _this.circlePath.hitTest(point, {
        segments: true,
        stroke: true,
        fill: false,
        tolerance: 10
      })
    } else {
      hitRes = _this.path.hitTest(point, {
        segments: true,
        stroke: true,
        fill: false,
        tolerance: 10
      })
    }
    if (hitRes) {
      return _this.option.type == 'circle' ? _this.circlePath : _this.path
    }
    return null
  }

  remove() {
    this.children.forEach(child => {
      child.remove()
    })

    if (this.text) {
      this.text.remove()
    }

    if (this.pointObjectList) {
      this.pointObjectList.forEach(o => {
        o.remove()
      })
    }

    if (this.path) {
      this.path.remove()
    }
    if (this.circlePath) {
      this.circlePath.remove()
    }
  }

  /**
   * 判断路径是否完全相同，使用points 数据判断
   * @param {*} annotation 用来对比的 annotation 对象
   */
  equals(annotation) {
    if (annotation.points == this.points) {
      return true
    }

    const len = annotation.points.length
    if (len != this.points.length) {
      return false
    }

    const result = _.intersectionBy(annotation.points, this.points, o => `${o.x}_${o.y}`)
    return result.length == len
  }
}
